package dmp_report

import (
	"context"
	"crypto/md5"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/errcode"
	"git.myscrm.cn/golang/common/ykerrcode"
	"git.myscrm.cn/golang/stark/v4"
	jwtpkg "github.com/golang-jwt/jwt"
	"net/url"
	"time"
)

type DmpReportService struct {
}

type DmpJwtClaims struct {
	TenantCode string `json:"tenant_code"`
	Account    string `json:"account"`
	Redirect   string `json:"redirect"`
	jwtpkg.StandardClaims
}

const (
	PathSsoLogin = "/api/user/sso/login"
)

func NewDmpReportService() DmpReportServiceIface {
	return &DmpReportService{}
}

// GetDmpPathByCode 获取 dmp 页面路径
// dmp的路径存储在配置中心以 dmp.page.(code) 格式，其中（code）根据约定由前端传来，如土地交易 code 为 land
// 存储在配置中心的 key 就相当于 dmp.page.land
// 如果取值取不到，则认为是无效的 code
func (d DmpReportService) GetDmpPathByCode(pageCode string) (string, error) {
	key := "dmp.page." + pageCode
	path := stark.Configer.(stark.ApolloConfigerIface).GetStringValue(key, "")
	if path == "" {
		return "", ykerrcode.TogRPCError(errcode.COMMON_DMP_INVALID_PAGE_CODE, "无效页面代码："+pageCode)
	}
	return path, nil
}

// GetSsoLoginUrl 获取单点登录地址
func (d DmpReportService) GetSsoLoginUrl(ctx context.Context, path string, params map[string]string) (string, error) {
	// 加密租户 code （这里为了避免各个租户的应用报告可以相互查看，特地加了一个加密 code 进行混淆，只作用于用户行为的报表）
	if value, ok := params["tenant_code"]; value != "" && ok {
		tenantToken := "JGgVjyCPM86qNSO6"
		tenantCodeHash := md5.Sum([]byte(params["tenant_code"]))
		tenantCodeHashHex := hex.EncodeToString(tenantCodeHash[:])

		// 将 tenantCode 的 MD5 哈希值和 tenantToken 拼接，并计算拼接后的字符串的 MD5 哈希值
		combinedString := tenantCodeHashHex + tenantToken
		resultHash := md5.Sum([]byte(combinedString))
		params["tenant_token"] = hex.EncodeToString(resultHash[:])
	}

	// 获取 dmp 参数
	dmpDomain := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("dmp.host", "")
	dmpTenantCode := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("dmp.tenant_code", "")
	dmpAccount := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("dmp.account", "")
	dmpSecret := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("dmp.secret", "")

	// 将参数放到 path 上
	values := url.Values{}
	for k, v := range params {
		values.Set(k, v)
	}
	targetUrl := dmpDomain + path + "&" + values.Encode()

	// 构建 jwt token
	// 设置有效期 7 天
	expire := time.Duration(10080) * time.Minute
	claims := &DmpJwtClaims{
		TenantCode: dmpTenantCode,
		Account:    dmpAccount,
		Redirect:   targetUrl,
		StandardClaims: jwtpkg.StandardClaims{
			IssuedAt:  time.Now().Unix(),
			ExpiresAt: time.Now().Add(expire).Unix(),
		},
	}
	token := jwtpkg.NewWithClaims(jwtpkg.SigningMethodHS256, claims)
	accessToken, err := token.SignedString([]byte(dmpSecret))
	if err != nil {
		stark.Logger.Errorf(ctx, "issue dmp token failed, err:%+v", err)
		return "", ykerrcode.TogRPCError(errcode.COMMON_DMP_ISSUE_TOKEN, "生成 token 失败：")
	}

	// 构建单点登录 url
	return fmt.Sprintf("%s%s?access_token=%s&_from=gfyx", dmpDomain, PathSsoLogin, base64.StdEncoding.EncodeToString([]byte(accessToken))), nil
}
